package com.imooc.zuul.filters;

import com.imooc.grance.result.GraceJsonResult;
import com.imooc.grance.result.ResponseStatusEnum;
import com.imooc.utils.IPUtil;
import com.imooc.utils.JsonUtils;
import com.imooc.utils.RedisOperator;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @Project_name: imooc-news-dev
 * @Description:
 * @Author: Levi
 * @Date: 2021/4/1 17:30
 */
@Component
@RefreshScope
public class BlackIpFilter extends ZuulFilter {
    @Autowired
    private RedisOperator redis;
    /**
     * 连续访问的次数
     */
    @Value("${blackIp.continueCounts}")
    private Integer continueCounts;
    /**
     * 规定的时间内
     */
    @Value("${blackIp.timeInteval}")
    private Integer timeInteval;

    /**
     * 限制的时间
     */
    @Value("${blackIp.limitTime}")
    private Integer limitTime;


    /**
     * 过滤器的类型
     * pre   在路由之前执行
     * route 在路由的时候执行
     * post  在路由之后执行
     * error 在处理请求时发生异常执行
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器的执行顺序 从小到大执行
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 2;
    }

    /**
     * 是否开启过滤器
     * true   开启
     * false  不开启
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 执行业务的代码放在这个方法里面
     *
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        System.out.println("限制ip黑名单的过滤器...");
        System.out.println("continueCounts: "+continueCounts);
        System.out.println("timeInteval: "+timeInteval);
        System.out.println("limitTime: "+limitTime);
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String ip = IPUtil.getRequestIp(request);
        final String ipRedisKey = "zuul-ip" + ":" + ip;
        final String ipRedisKeyLimit = "zuul-ip-limit" + ":" + ip;

        //进来时候先进来判断限制的时间还有没有，有的话不让访问   ,这一步不会先执行
        long limitLeftTime = redis.ttl(ipRedisKeyLimit);
        if (limitLeftTime > 0) {
            //ip还在限制当中，停止访问
            stopRequest(currentContext);
            return null;
        }
        //只要能获得请求次数   说明还在该请求10秒之内
        //判断请求是不是第一次进来，如果是请求第一次进来，则设置过期时间  10秒
        //意思就是从第一次登录开始计时，10秒,
        long readCounts = redis.increment(ipRedisKey, 1);
        if (readCounts == 1) {
            //这个key过期了之后还是从第一次开始访问
            redis.expire(ipRedisKey, timeInteval);
        }
        //如果在10秒内访问的次数超过10次，则将该ip加入黑名单限制15秒内不能访问
        if (readCounts > continueCounts) {
            redis.set(ipRedisKeyLimit, ipRedisKeyLimit, limitTime);
            stopRequest(currentContext);
        }

        return null;
    }

    private void stopRequest(RequestContext context) {
        //设置false表示停止当前访问
        context.setSendZuulResponse(false);
        context.setResponseStatusCode(200);
        String result = JsonUtils.objectToJson(GraceJsonResult.errorCustom(ResponseStatusEnum.SYSTEM_LIMIT_IP));
        context.setResponseBody(result);
        context.getResponse().setCharacterEncoding("utf-8");
        context.getResponse().setContentType(MediaType.APPLICATION_JSON_VALUE);
    }
}
